package log

import (
	"encoding/json"
	"fmt"
	"strings"

	"github.com/spf13/pflag"
)

const (
	flagLevel             = "log.level"
	flagDisableCaller     = "log.disable-caller"
	flagDisableStacktrace = "log.disable-stacktrace"
	flagFormat            = "log.format"
	flagEnableColor       = "log.enable-color"
	flagOutputPaths       = "log.output-paths"
	flagErrorOutputPaths  = "log.error-output-paths"
	flagDevelopment       = "log.development"
	flagName              = "log.name"

	consoleFormat = "console"
	jsonFormat    = "json"
)

type Options struct {
	Level       string `json:"level"               mapstructure:"level"`
	Format      string `json:"format"              mapstructure:"format"`
	EnableColor bool   `json:"enable-color"        mapstructure:"enable-color"`
	// DisableCaller 禁止打印调用者。
	DisableCaller bool `json:"disable-caller"      mapstructure:"disable-caller"`
	// DisableStacktrace 禁止打印错误栈。
	DisableStacktrace bool `json:"disable-stacktrace"  mapstructure:"disable-stacktrace"`
	// OutputPaths 将应用日志输出到指定通道，默认为 stdout 。
	OutputPaths []string `json:"output-paths"        mapstructure:"output-paths"`
	// ErrorOutputPaths 将内部错误输出到指定通道，默认为 stderr 。
	// 在此配置中输出日志的示例已经在社区中提问：
	// [discussions](https://github.com/uber-go/zap/discussions/1400)
	ErrorOutputPaths []string `json:"error-output-paths"  mapstructure:"error-output-paths"`
	// Development 开发模式，此模式下将从 warn 级别开始打印错误栈，并在 dpanic
	// 级别完成日志打印后以返回码1退出。
	Development bool   `json:"development"         mapstructure:"development"`
	Name        string `json:"name"                mapstructure:"name"`
}

// NewOptions 构造了默认配置。
func NewOptions() *Options {
	return &Options{
		Level:             InfoLevel.String(),
		Format:            consoleFormat,
		EnableColor:       false,
		DisableCaller:     false,
		DisableStacktrace: false,
		OutputPaths:       []string{"stdout"},
		ErrorOutputPaths:  []string{"stderr"},
		Development:       false,
	}
}

// Validate 校验 Level 与 Format 。
func (o *Options) Validate() []error {
	var errs []error

	var level Level

	if err := level.UnmarshalText([]byte(o.Level)); err != nil {
		errs = append(errs, err)
	}

	format := strings.ToLower(o.Format)
	if format != consoleFormat && format != jsonFormat {
		errs = append(errs, fmt.Errorf("not a valid log format: %q", o.Format))
	}

	return errs
}

// AddFlags 添加命令行参数。
func (o *Options) AddFlags(fs *pflag.FlagSet) {
	fs.StringVar(&o.Level, flagLevel, o.Level, "Minimum log output `LEVEL`.")
	fs.BoolVar(&o.DisableCaller, flagDisableCaller, o.DisableCaller,
		"Disable output of caller information in the log.")
	fs.BoolVar(&o.DisableStacktrace, flagDisableStacktrace, o.DisableStacktrace,
		"Disable the log to record a stack trace for all message at or above panic level.")
	fs.StringVar(&o.Format, flagFormat, o.Format,
		"log output `FORMAT`, support plain or json format.")
	fs.BoolVar(&o.EnableColor, flagEnableColor, o.EnableColor,
		"Enable output ansi colors in plain formats logs.")
	fs.BoolVar(&o.Development, flagDevelopment, o.Development,
		"Development puts the logger in development mode, which changes "+
			"the behavior of DPanicLevel and takes stacktrace more liberally.")
	fs.StringSliceVar(&o.OutputPaths, flagOutputPaths, o.OutputPaths, "Output path of log.")
	fs.StringSliceVar(&o.ErrorOutputPaths, flagErrorOutputPaths, o.ErrorOutputPaths,
		"Error output paths of log.")
}

// String 方法参考：
// [Stringer](https://pkg.go.dev/fmt#Stringer)
// [Go中类型的String方法](https://blog.csdn.net/huanyi5214/article/details/111259390)

// String 方法实现了 Stringer 接口，将类型打印为 json 字符串。
func (o *Options) String() string {
	data, _ := json.Marshal(o)

	return string(data)
}
